/*************************************************************************
 *                                                                       *
 * This file is part of the FreeMAPs distribution.  For full copyright   *
 * information, see COPYRIGHT and COPYING.LESSER.                        *
 *                                                                       *
 * Author:           sqbang                                              *
 * Email:            sqbang@ustc.edu                                     *
 * Date:             2013.06.02                                          *
 *                                                                       *
 *************************************************************************/

//declaration header
#include "COMMON/base/StateIndicator.h"

//COMMON headers
#include "COMMON/info/InfoManager.h"
#include "COMMON/info/CommonInfo.h"
#include "COMMON/tbox/LogMessage.h"

namespace FreeMAPs
{

StateIndicator::StateIndicator(
    const std::string& parent_name,
    const std::string& object_name,
    const bool is_registered_in_info_manager):
    d_full_name (parent_name + "-->" + object_name),
    d_object_name (object_name),
    d_is_registered_in_info_manager (is_registered_in_info_manager),
    d_verbose_level (FREEMAPS_INVALID_VALUE),
    d_database (NULL)
{
    /*
     * parent name can be empty, so do NOT check it.
     */
    FREEMAPS_ASSERT (!parent_name.empty());
    FREEMAPS_ASSERT (!object_name.empty());

    /*
     * usually set the differentiald object's state to good for use.
     * if the differentiald object require rebuid or reinit.
     * set it to bad until finished rebuild.
     */
    d_state = State::BAD;

    if (d_is_registered_in_info_manager)
    {
        InfoManager::get_instance()->register_state_indicator (this);
    }
}



StateIndicator::~StateIndicator()
{
    /*
     * all state indicators have registered in the InfoManager for check_consistence.
     * so if copy function is called, a lot of NULL pointer will exists when destructor.
     * remove those NULL pointer to avoid the check NULL pointer's consistence.
     */
    if (d_is_registered_in_info_manager)
    {
        InfoManager::get_instance()->remove_state_indicator (this);
    }
}



bool
StateIndicator::is_prepared() const
{
    return (d_state == State::GOOD);
}



void
StateIndicator::check_state()const
{
    if (d_state != State::GOOD)
    {
        //const_cast<StateIndicator*>(this)->rebuild_rely_on_mesh();
    }
}



void
StateIndicator::attach_database (
    const InputDatabase* db)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);

    d_database = db;
}



const InputDatabase*
StateIndicator::get_database() const
{
    FREEMAPS_ASSERT_VALID_POINTER (d_database);

    return d_database;
}



std::string
StateIndicator::get_location() const
{
    if (d_database)
    {
        std::ostringstream oss;
        oss << d_database->get_file_name() << " --> " << d_database->get_nested_name();
        return oss.str();
    }
    else
    {
        return d_full_name;
    }
}



bool
StateIndicator::require_show_verbose_info(
    const int required_least_level) const
{
if (d_verbose_level < 0)
{
	int i = 0;
	++i;
}
    FREEMAPS_ASSERT (d_verbose_level >= 0);

    if (d_verbose_level >= required_least_level)
    {
        return true;
    }
    else
    {
        return false;
    }
}



void
StateIndicator::show_verbose_info (
    const std::string& info,
    const int required_least_level) const
{
    if (this->require_show_verbose_info (required_least_level))
    {
        LogMessage::show_verbose_info (info);
    }
}



void
StateIndicator::check_consistence()const
{
    FREEMAPS_ERROR ("function of \"check_consistence()\" should be implement in the derived object of \"" << d_full_name << "\"");
}



void
StateIndicator::check_all_consistence() const
{
    for (std::map<std::string, std::pair<bool, std::string> >::const_iterator pos = d_keys_to_be_checked_consistence.begin();
            pos != d_keys_to_be_checked_consistence.end(); ++pos)
    {
        if (!pos->second.first)
        {
            FREEMAPS_ERROR ("in object of \""
                            << d_full_name
                            << "\", the key \""
                            << pos->first
                            << "\" has not been checked\n"
                            << pos->second.second);
        }
    }
}



void
StateIndicator::prepare_for_use(
    const InputDatabase* db)
{
    if (db)
    {
        this->attach_database (db);
        this->get_common_from_input (db);
    }
}



void
StateIndicator::prepare_for_use_from_parent_database(
    const InputDatabase* parent_db)
{
    this->update_state (State::GOOD);

    FREEMAPS_ASSERT_VALID_POINTER (parent_db);
    this->attach_database (parent_db);
}



void
StateIndicator::get_common_from_input (
    const InputDatabase* db)
{
    if (d_verbose_level >= 0)
    {
        db->insert_allowable_key ("verbose_level");

        /*
         * do not check the allowable keys,
         * they should be checked in the derived object.
         */

        /*
         * build verbose_level
         */
        db->check_optional_key ("verbose_level", DataType::INTEGER, true, false);
        db->check_allowable_integer_value ("verbose_level", 0, 10);
        if (d_verbose_level == 0)
        {
            d_verbose_level = InfoManager::get_instance()->get_common_info()->get_verbose_level();
        }

        d_verbose_level = db->get_integer_with_default ("verbose_level", d_verbose_level);
    }
}

}
